﻿/**
https://stackoverflow.com/questions/19620667/javascript-operator-overloading
https://blog.csdn.net/green_dream123/article/details/122827749
*/

function StringBuilder(array) {
    this.arr = [];
    if (typeof array == "undefined") {
        //Do Nothing
    }
    else if (array instanceof Array || Array.isArray(array)) {
        if (true) {
            let variable = this;
            array.forEach(function (item) {
                variable.arr.push(item);/* 此范围内不能使用this */
            });
        } else {
            Array.prototype.push.apply(arr, array);
        }
    } else if ((array instanceof String) || typeof (array).toLowerCase() == 'string' || array.constructor == String) {
        this.arr.push(array);
    } else {
        this.arr.push(array.toString());
    }

    /**
     * 闭包实现方法重载
     * @param {any} obj
     * @param {any} name
     * @param {any} fnc
     */
    var method = function (obj, name, fnc) {
        var old = obj[name];
        obj[name] = function () {
            if (arguments.length === fnc.length) {
                return fnc.apply(this, arguments);
            } else if (typeof old === "function") {
                return old.apply(this, arguments);
            }
        }
    }
    method(this, "appendFormat", function () {
        this.arr.push("");
        return this;
    });
    method(this, "appendFormat", function (arg) {
        let matchs = undefined;
        if (arg == undefined) {
            throw "参数未定义" + arg.name;
        }
        else if ((matchs = arg.match(/\{\d+\}/g)) == null) {
            this.arr.push(arg);
        }
        if (matchs.length > 0) {
            throw "索引(从零开始)必须大于或等于零，且小于参数列表的大小。";
        }
        return this;
    });
    method(this, "appendFormat", function (arg1, arg2) {
        if (arguments.length == 0) {
            this.arr.push("");
        }
        else if (arguments.length > 1) {
            let matchs = undefined;
            if (arguments[0] == undefined) {
                throw "参数未定义";
            } else if ((matchs = arguments[0].match(/\{\d+\}/g)) == null) {
                this.arr.push(arg);
            } else if (matchs.length > 0) {
                let tempStr = arguments[0];
                matchs.forEach((value, index, array) => {
                    let num = Number(value.match(/\d+/));
                    if (num < arguments.length - 1) {
                        tempStr = tempStr.replace(value, arguments[index + 1]);
                    }
                });
                this.arr.push(tempStr);
            }
        }
        return this;
    });
}

StringBuilder.prototype = {
    append: function () {
        let variable = this;
        let func0 = function () {
            variable.arr.push("");/* 此范围内不能使用this */
        }
        let func1 = function (arg) {
            variable.arr.push(arg);/* 此范围内不能使用this */
        }
        if (arguments.length === 0) {
            func0();
        } else if (arguments.length === 1) {
            func1(arguments[0]);
        }
        return this;
    },
    appendLine: function () {
        // function map for our overloads
        var fnMap = {};

        fnMap[0] = function () {
            this.arr.push("\r\n");
            return this;
        }

        fnMap[1] = function (arg) {
            this.arr.push(arg + "\r\n");
            return this;
        };
        //    redefine the function using the fnMap in the closure
        this.multiFn = function () {
            fnMap[arguments.length].apply(this, arguments);
            return this;
        };

        //    call the function since this code will only run once
        this.multiFn.apply(this, arguments);
        return this;
    },
    appendFormat1: function (...args) {
        if (arguments.length == 0) {
            this.arr.push("");
        } else if (arguments.length == 1) {
            this.arr.push(arguments[0]);
        }
        else {
            let matchs = undefined;
            if (arguments[0] == undefined) {
                throw "参数未定义";
            } else if ((matchs = arguments[0].match(/\{\d+\}/g)) == null) {
                this.arr.push(arg);
            } else if (matchs.length > 0) {
                let tempStr = arguments[0];
                matchs.forEach((value, index, array) => {
                    let num = Number(value.match(/\d+/));
                    if (num < arguments.length - 1) {
                        tempStr = tempStr.replace(value, arguments[index + 1]);
                    }
                });
                this.arr.push(tempStr);
            }
        }
        return this;
    },
    toString: overload(
        function () {
            return this.arr.join('');
        },
        function (split) {
            return this.arr.join(split);
        }
    )
};

/**
 * 重载方法
 * @param {any} value
 * @param {any} index
 * @param {any} self
 */
function onlyUnique(value, index, self) {
    return self.indexOf(value) === index;
}
/** 重载方法 */
function overload() {
    var functions = arguments;
    var nroffunctionsarguments = [arguments.length];
    for (var i = 0; i < arguments.length; i++) {
        nroffunctionsarguments[i] = arguments[i].length;
    }
    var unique = nroffunctionsarguments.filter(onlyUnique);
    if (unique.length === arguments.length) {
        return function () {
            var indexoffunction = nroffunctionsarguments.indexOf(arguments.length);
            return functions[indexoffunction].apply(this, arguments);
        }
    }
    else throw new TypeError("There are multiple functions with the same number of parameters");
}